home *** CD-ROM | disk | FTP | other *** search
- #import "MartinView.h"
- #import "Thinker.h"
- #import <math.h>
- #import <libc.h>
- #import <streams/streams.h>
- #import <defaults/defaults.h>
- #import <appkit/color.h>
- #import <appkit/graphics.h>
- #import <dpsclient/wraps.h>
- #import <appkit/Button.h>
- #import <appkit/Application.h>
-
- /* MartinView: a BackSpace.app v3.0 module by Jeffrey Adams
- * version 1.0 jeffa@wri.com
- */
-
- char fname[Nfunc][16] = { "martin1", "martin2", "ejk1", "ejk2" };
-
- /* The file used to store remembered fractals */
- char fileName[] = "/.martinView";
-
- @implementation MartinView
-
- /* Implemented so you can screen grab the image if you want to (at least I wanted to!) */
- - pause:sender
- {
- isPaused = [sender state];
- return self;
- }
-
- /* Inherited method for setting the graphics state before sending OneSteps */
- - didLockFocus
- {
- NXSetColor(currColor);
- return self;
- }
-
- - oneStep
- {
- NXRect *currentPixel = pixels;
-
- if (isPaused) return self;
-
- /* Stay in here until we hit our flush buffer limit or we hit the maximum
- total points allowed */
- while ((++nd < nD) && (++nP < mxP)) {
-
- switch (Function) {
- case Ejk1: x1 = y - ( (x>0) ? (B*x-C) : -(B*x-C) ); break;
- case Martin1: x1 = y - ( (x<0) ? sqrt(fabs(B*x-C)) : -sqrt(fabs(B*x-C)) ); break;
- case Ejk2: x1 = y - ( (x<0) ? log(fabs(B*x-C)) : -log(fabs(B*x-C)) ); break;
- case Martin2: x1 = y - sin(x); break;
- }
- y = A - x; x=x1;
-
- /* seed perturbation */
- if (Pn && ++pn > Pn) {
- x += (x>0) ? -Pv : Pv;
- y += (y>0) ? -Pv : Pv;
- pn = 0;
- }
-
- /* Do we need to change the color? */
- if (++nc > nC) {
- color = (color+1)%Ncolors;
- /* Since we are changing color, send buffered points to screen */
- if (numPixels) {
- NXRectFillList(pixels, numPixels);
- numPixels = 0; currentPixel = pixels;
- }
- currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) :
- NXConvertGrayToColor(Ranf())) : colors[color];
- NXSetColor(currColor);
- nc = 0;
- }
-
- /* If we are not within the screen range, do not store them */
- iy = cy + Zf*y; if (iy < 0 || iy > mxY) continue;
- ix = cx + Zf*x; if (ix < 0 || ix > mxX) continue;
-
- /* Update the data needed for the NXRectFillList */
- currentPixel->origin.x = ix; currentPixel->origin.y = iy;
- ++numPixels; ++currentPixel;
-
- /* Have we hit the in-range limit, if so, send the buffer to the screen */
- if (++np > mxp) {
- if (numPixels) {
- NXRectFillList(pixels, numPixels);
- numPixels = 0; currentPixel = pixels;
- }
- [self newOne:self];
- break;
- }
- }
- nd = 0;
- /* Flush buffer full, display pixels */
- if (numPixels) {
- NXRectFillList(pixels, numPixels);
- numPixels = 0; currentPixel = pixels;
- }
- /* If we left because we hit max total limit, give us a new one */
- if(nP == mxP)
- [self newOne:self];
- return self;
- }
-
- - newOne:sender
- {
- double A1, B1, C1; /* 2nd part of parameter range */
- char name[15],str[20];
- NXStream *stream;
- int i;
-
- [self display];
- if (!smallInspect) return nil;
-
- /* Record current settings in Defaults database */
- sprintf(str,"%d", ([funcAuto state]) ? -1 : Function);
- NXWriteDefault([NXApp appName], "MartinFunction", str);
- sprintf(str,"%d", ([maxTotFlag state]) ? -1 : [maxTotalPts intValue]);
- NXWriteDefault([NXApp appName], "MartinMaxTot", str);
- sprintf(str,"%d", ([maxInFlag state]) ? -1 : [maxInRangePts intValue]);
- NXWriteDefault([NXApp appName], "MartinMaxIn", str);
- sprintf(str,"%d", ([colFlag state]) ? -1 : [colInterval intValue]);
- NXWriteDefault([NXApp appName], "MartinColorInt", str);
-
- np = 0; nP = 0; nd = 0; numPixels=0;
- x = y = 0; color = -1;
- Ranfset(time(0));
- W = (int)bounds.size.width;
- H = (int)bounds.size.height;
- mxX = W-1; mxY = H-1;
-
- /* If we are using a file, load the settings from '.martinView' */
- if (streamPos >= 0) {
- if (!(stream = NXMapFile(file, NX_READONLY))) {
- streamPos = -1;
- [useFileFlag setState:NO];
- [self newOne:self];
- return self;
- }
- for (i=0; i <= streamPos; ++i) {
- if(NXAtEOS(stream)){
- streamPos = 0; i=-1;
- NXSeek(stream, 0, NX_FROMSTART);
- if(NXAtEOS(stream)) {
- streamPos =-1;
- [useFileFlag setState:NO];
- [self newOne:self];
- return self;
- }
- continue;
- }
- NXScanf(stream, "%s\n",name);
- NXScanf(stream, "%d %le\n",&Pn,&Pv);
- NXScanf(stream, "%d\n",&Function);
- NXScanf(stream, "%le %le %le %le\n",&A,&B,&C,&Zf);
- NXScanf(stream, "%d %d %d\n",&mxp,&mxP,&nC);
- NXScanf(stream, "%d %d\n",&moveX,&moveY);
- }
- streamPos++;
- NXCloseMemory(stream, NX_FREEBUFFER);
- }
- else {
-
- if ([seedIntFlag state]) Pn = pow(10., 1+Ranf()*3);
- else Pn = [seedPertInt intValue];
- if ([seedValFlag state]) Pv = pow(10.,Ranf()*3);
- else Pv = [seedPertVal doubleValue];
-
- /* provide default hopalong parameters if needed */
- if ([funcAuto state]) {
- double r = Ranf();
- if (r < 0.40) Function = Martin1;
- else if (r < 0.70) Function = Ejk1;
- else if (r < 0.90) Function = Ejk2;
- else Function = Martin2;
- }
- if (Function == Martin1) {
- if ([aFlag state]) A = 40 + Ranf()*1500;
- if ([bFlag state]) B = 3 + Ranf()*17;
- if ([cFlag state]) C = 100 + Ranf()*3000;
- }
- else if (Function == Martin2) {
- if ([aFlag state]) A = 3.075927 + Ranf()*0.14;
- }
- else if (Function == Ejk1) {
- if ([aFlag state]) A = Ranf()*500;
- if ([bFlag state]) B = Ranf()*.40;
- if ([cFlag state]) C = 10 + Ranf()*100;
- }
- else if (Function == Ejk2) {
- if ([aFlag state]) A = Ranf()*500;
- if ([bFlag state]) B = pow(10.,6+Ranf()*24);
- if ([cFlag state]) C = pow(10., Ranf()*9);
- }
- if(![aFlag state]) A = [hopAField doubleValue];
- if(![bFlag state]) B = [hopBField doubleValue];
- if(![cFlag state]) C = [hopCField doubleValue];
-
- if (A1 = [a1Flag state]) A = Min(A,A1) + Ranf()*(Max(A,A1) - Min(A,A1));
- if ([afFlag state] && Ranf()<0.5) A = -A;
- if (B1 = [b1Flag state]) B = Min(B,B1) + Ranf()*(Max(B,B1) - Min(B,B1));
- if ([bfFlag state] && Ranf()<0.5) B = -B;
- if (C1 = [c1Flag state]) C = Min(C,C1) + Ranf()*(Max(C,C1) - Min(C,C1));
- if ([cfFlag state] && Ranf()<0.5) C = -C;
-
- if ([magFlag state]) Zf = (Function == Martin2) ? 4.0 : 1.0;
- else Zf = [magField doubleValue];
-
- if ([maxInFlag state]) mxp = (int) (0.40* (float)(W*H));
- else mxp = [maxInRangePts intValue];
- if ([maxTotFlag state]) mxP = 4 * mxp;
- else mxP = [maxTotalPts intValue];
-
- /* color processing */
- if ([colFlag state]) nC = (mxP/Ncolors)/2;
- else nC = [colInterval intValue];
- }
- nc = nC;
- cx = W/2+moveX; cy = H/2+moveY;
- [displaceX setIntValue:moveX];
- [displaceY setIntValue:moveY];
- [seedPertInt setIntValue:Pn];
- [seedPertVal setDoubleValue:Pv];
- [dynamFlush setIntValue:nD];
- [funcButton setTitle:fname[Function]];
- [hopAField setDoubleValue:A];
- [hopBField setDoubleValue:B];
- [hopCField setDoubleValue:C];
- [magField setDoubleValue:Zf];
- [maxInRangePts setIntValue:mxp];
- [maxTotalPts setIntValue:mxP];
- [colInterval setIntValue:nC];
- return self;
- }
-
- - changeFunc:sender
- {
- char str[10];
-
- Function = [sender selectedTag];
- [funcAuto setState:NO];
- sprintf(str,"%d", Function);
- NXWriteDefault([NXApp appName], "MartinFunction", str);
- [self newOne:sender];
- return self;
- }
- - changeDynam:sender
- {
- nD = [sender intValue];
- if ((nD <1) || (nD > MAXDYNAMPOINTS))
- nD = MAXDYNAMPOINTS;
- [dynamFlush setIntValue:nD];
- [self makeNewDynam:nD];
- [self newOne:sender];
- return self;
- }
-
- /* We create the array of NXRects ahead of time so we do not waste time
- building the array up as we go along */
- - makeNewDynam:(int)num
- {
- NXRect *curr;
- NXSize pixSize = {1,1};
-
- if (pixels)
- free(pixels);
- pixels = (NXRect *)malloc(sizeof(NXRect)*(num+1));
- for (curr = pixels; curr-pixels < num; ++curr)
- curr->size = pixSize;
- return self;
- }
- - setHopA:sender
- {
- if ([sender doubleValue] > 0) [aFlag setState:NO];
- [self newOne:sender];
- return self;
- }
- - setHopB:sender
- {
- if ([sender doubleValue] > 0) [bFlag setState:NO];
- [self newOne:sender];
- return self;
- }
- - setHopC:sender
- {
- if ([sender doubleValue] > 0) [cFlag setState:NO];
- [self newOne:sender];
- return self;
- }
-
- - setSeedInt:sender
- {
- if ([sender intValue] > 0) [seedIntFlag setState:NO];
- [self newOne:sender];
- return self;
- }
- - setMagnification:sender
- {
- if ([sender doubleValue] >= 0) [magFlag setState:NO];
- [self newOne:sender];
- return self;
- }
-
- - setSeedVal:sender
- {
- if ([sender doubleValue] >= 0) [seedValFlag setState:NO];
- [self newOne:sender];
- return self;
- }
- - setDisplacement:sender
- {
- moveX = [displaceX intValue];
- moveY = [displaceY intValue];
- [self newOne:sender];
- return self;
- }
-
- - setColChange:sender
- {
- char str[30];
-
- if ([sender intValue] > 0) {
- [colFlag setState:NO];
- sprintf(str,"%d", [sender intValue]);
- NXWriteDefault([NXApp appName], "MartinColorInt", str);
- }
- [self newOne:sender];
- return self;
- }
-
- - setMaxTot:sender
- {
- char str[30];
-
- if ([sender intValue] > 0) {
- [maxTotFlag setState:NO];
- sprintf(str,"%d", [sender intValue]);
- NXWriteDefault([NXApp appName], "MartinMaxTot", str);
- }
- [self newOne:sender];
- return self;
- }
- - setMaxIn:sender
- {
- char str[30];
-
- if ([sender intValue] > 0) {
- [maxInFlag setState:NO];
- sprintf(str,"%d", [sender intValue]);
- NXWriteDefault([NXApp appName], "MartinMaxIn", str);
- }
- [self newOne:sender];
- return self;
- }
- - setRandomColor:sender
- {
- char str[10];
-
- Randomcolor = [sender state];
- sprintf(str,"%d", Randomcolor);
- NXWriteDefault([NXApp appName], "MartinRandomCol", str);
- [self newOne:sender];
- return self;
- }
- - changeColorMode:sender
- {
- int newColMode;
- char str[10];
-
- newColMode = [sender selectedTag];
- if (Color != newColMode) {
- Color = newColMode;
- [self convertColors];
- sprintf(str,"%d",Color);
- NXWriteDefault([NXApp appName], "MartinColorMode", str);
- }
- [self newOne:self];
- return self;
- }
-
- /* Weak way of changing from nonrandom color array to nonrandom gray array */
- - convertColors
- {
- if (Color){
- Ncolors = DEFAULTNUMCOLORS;
- colors[0] = NX_COLORBLUE;
- colors[1] = NX_COLORBROWN;
- colors[2] = NX_COLORWHITE;
- }
- else{
- Ncolors = 3;
- colors[0] = NX_COLORWHITE;
- colors[1] = NX_COLORDKGRAY;
- colors[2] = NX_COLORLTGRAY;
- }
- return self;
- }
-
- /* Append the current fractal info (all of it) in the data file */
- - remember:sender
- {
- NXStream *stream;
-
- if (!(stream = NXMapFile(file, NX_WRITEONLY))) {
- stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- }
- NXSeek(stream, 0, NX_FROMEND);
- NXPrintf(stream, "MartinView\n");
- NXPrintf(stream, "%d %.15le\n",Pn,Pv);
- NXPrintf(stream, "%d\n",Function);
- NXPrintf(stream, "%.15le %.15le %.15le %.15le\n",A,B,C,Zf);
- NXPrintf(stream, "%d %d %d\n",mxp,mxP,nC);
- NXPrintf(stream, "%d %d\n",moveX,moveY);
- NXSaveToFile(stream, file);
- NXCloseMemory(stream, NX_FREEBUFFER);
- return self;
- }
-
- - useFile:sender
- {
- NXStream *stream;
- char name[15],str[10];
-
- if ([sender state]) {
- if (!(stream = NXMapFile(file, NX_READONLY))) {
- [sender setState:NO];
- streamPos = -1;
- [self newOne:self];
- }
- else {
- NXScanf(stream, "%s\n",name);
- if (strcmp("MartinView",name)) {
- [sender setState:NO];
- streamPos = -1;
- }
- else streamPos = 0;
- NXCloseMemory(stream, NX_FREEBUFFER);
- [self newOne:self];
- }
- }
- else {
- streamPos = -1;
- [self newOne:self];
- }
- sprintf(str,"%d",[sender state]);
- NXWriteDefault([NXApp appName], "MartinUseFile", str);
- return self;
- }
-
- - initFrame:(NXRect *)frameRect
- {
- [super initFrame:frameRect];
-
- [self allocateGState]; // For faster lock/unlockFocus
- strcpy(file,NXHomeDirectory());
- strcat(file,fileName);
- srandom(getpid());
- isPaused = 0;
- Ncolors = DEFAULTNUMCOLORS;
- colors = (NXColor *)malloc(sizeof(NXColor)*Ncolors);
- colors[0] = NX_COLORBLUE;
- colors[1] = NX_COLORBROWN;
- colors[2] = NX_COLORWHITE;
- colors[3] = NX_COLORCYAN;
- colors[4] = NXConvertRGBToColor(250,128, 114);
- colors[5] = NX_COLORGRAY;
- colors[6] = NX_COLORGREEN;
- colors[7] = NXConvertRGBToColor(255,87, 33);
- colors[8] = NX_COLORMAGENTA;
- colors[9] = NX_COLORORANGE;
- colors[10] = NX_COLORPURPLE;
- colors[11] = NX_COLORRED;
- colors[12] = NXConvertRGBToColor(227,207, 87);
- colors[13] = NX_COLORYELLOW;
- moveX = 0; moveY = 0;
- Ranfseed=4326;
- nD = STARTDYNAMPOINTS;
- [self makeNewDynam:nD];
- return self;
- }
-
- - inspectorWillBeRemoved
- {
- [myPrefPanel orderOut:self];
- return self;
- }
-
- - inspector:sender
- {
- char buf[MAXPATHLEN];
- int value;
-
- if (!smallInspect)
- {
- sprintf(buf,"%s/MartinPrefs.nib",[sender moduleDirectory:"Martin"]);
- [NXApp loadNibFile:buf owner:self withNames:NO];
- Function=atoi(NXGetDefaultValue([NXApp appName], "MartinFunction"));
- if (Function == -1)
- [funcAuto setState:YES];
- else {
- [funcAuto setState:NO];
- [funcButton setTitle:fname[Function]];
- }
- if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxTot"))) == -1)
- [maxTotFlag setState:YES];
- else {
- [maxTotFlag setState:NO];
- [maxTotalPts setIntValue:value];
- }
- if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxIn"))) == -1)
- [maxInFlag setState:YES];
- else {
- [maxInFlag setState:NO];
- [maxInRangePts setIntValue:value];
- }
- if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinColorInt"))) == -1)
- [colFlag setState:YES];
- else {
- [colFlag setState:NO];
- [colInterval setDoubleValue:value];
- }
- Randomcolor = atoi(NXGetDefaultValue([NXApp appName], "MartinRandomCol"));
- [randomFlag setState:Randomcolor];
- Color=atoi(NXGetDefaultValue([NXApp appName], "MartinColorMode"));
- if (Color) [colorButton setTitle:"Color"];
- else [colorButton setTitle:"Mono"];
- [self convertColors];
- currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) :
- NXConvertGrayToColor(Ranf())) : colors[0];
- [useFileFlag setState:atoi(NXGetDefaultValue([NXApp appName], "MartinUseFile"))];
- if ([useFileFlag state])
- [self useFile:useFileFlag];
- else {
- streamPos =-1;
- [self newOne:self];
- }
- }
- return smallInspect;
- }
-
- + initialize
- {
- static NXDefaultsVector MartinViewDefaults = {{"MartinFunction", "-1"},
- {"MartinMaxTot", "-1"},{"MartinMaxIn", "-1"},
- {"MartinColorInt", "-1"},{"MartinRandomCol", "1"},{"MartinColorMode", "1"},
- {"MartinUseFile", "0"},{NULL,NULL} };
- NXRegisterDefaults([NXApp appName], MartinViewDefaults);
- return self;
- }
-
- - sizeTo:(NXCoord)width :(NXCoord)height
- {
- [super sizeTo:width :height];
- [self newOne:self];
- return self;
- }
-
- - drawSelf:(const NXRect *)rects :(int)rectCount
- {
- if (!rects || !rectCount) return self;
- PSsetgray(0.0);
- NXRectFill(rects); // black screen
- return self;
- }
-
- - free
- {
- if (pixels)
- free(pixels);
- if (Ncolors)
- free(colors);
- return [super free];
- }
-
- /* Why not a little fluff */
- - windowWillMiniaturize:sender toMiniwindow:miniwindow
- {
- [sender setMiniwindowIcon:"MartinMini"];
- return self;
- }
-
- - (BOOL) useBufferedWindow { return NO; }
- - (const char *) windowTitle { return ( const char * ) "Martin Fractals";}
-
- @end
-